package com.intramirror.product.controller;

import com.intramirror.core.common.exception.ValidateException;
import com.intramirror.core.common.response.ErrorResponse;
import com.intramirror.core.common.response.Response;
import com.intramirror.core.common.response.StatusCode;
import static com.intramirror.product.constant.AggregateConstant.TYPE_MOVE_TO_EXISTS_SPU;
import com.intramirror.product.entity.Product;
import com.intramirror.product.entity.Spu;
import com.intramirror.product.entity.SpuAggregateLog;
import com.intramirror.product.entity.SpuExceptionProduct;
import com.intramirror.product.service.IProductService;
import com.intramirror.product.service.ISpuLogService;
import com.intramirror.product.service.ISpuService;
import com.intramirror.product.utils.ConvertUtil;
import com.intramirror.product.utils.SpuLogUtil;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.http.HttpStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.SessionAttribute;

/**
 * Created on 2018/1/21.
 * @author Admin
 */
@RestController
public class SpuController {

    private final static Logger LOGGER = LoggerFactory.getLogger(SpuController.class);
    @Autowired
    DiscoveryClient discoveryClient;

    @Autowired
    ISpuService spuService;

    @Autowired
    IProductService productService;

    @Autowired
    ISpuLogService spuLogService;

    @RequestMapping(value = "/test", method = RequestMethod.GET)
    @ResponseStatus(HttpStatus.OK)
    public void test(@SessionAttribute(value = "user") Map<String, Object> user) {
        LOGGER.info("SessionAttribute user : {}", user);
    }

    @RequestMapping("/getSpuById")
    public String getSpuById() {
        Spu s = spuService.getSpuById(12L);
        if (s != null) {
            return s.toString();
        } else {
            return "no spu found";
        }
    }

    @RequestMapping("/spus")
    public Response getSpuListByCond(@RequestParam(value = "spuId", required = false) Long spuId,
            @RequestParam(value = "isExact", required = false) Integer isExact, @RequestParam(value = "designerId", required = false) String designerId,
            @RequestParam(value = "colorCode", required = false) String colorCode, @RequestParam(value = "spuName", required = false) String spuName,
            @RequestParam(value = "begLastUpdated", required = false) Long begLastUpdated,
            @RequestParam(value = "endLastUpdated", required = false) Long endLastUpdated, @RequestParam(value = "brandId", required = false) Integer brandId,
            @RequestParam(value = "seasonCode", required = false) String seasonCode, @RequestParam(value = "image", required = false) Integer image,
            @RequestParam(value = "pageSize", required = false) Integer pageSize, @RequestParam(value = "pageNumber", required = false) Integer pageNo,
            @RequestParam(value = "orderBy", required = false) String orderBy, @RequestParam(value = "desc", required = false) String desc) {

        Map<String, Object> condMap = new HashMap<>();

        int start = ((pageNo == null || pageNo < 0) ? 0 : (pageNo - 1) * pageSize);
        int limit = ((pageSize == null || pageSize < 0) ? 25 : pageSize);

        condMap.put("spuId", spuId);
        condMap.put("isExact", isExact);
        condMap.put("start", start);
        condMap.put("limit", limit);
        condMap.put("designerId", designerId);
        condMap.put("colorCode", colorCode);
        condMap.put("seasonCode", seasonCode);
        condMap.put("spuName", spuName);
        if (begLastUpdated != null) {
            condMap.put("begLastUpdated", begLastUpdated / 1000);
        }

        if (endLastUpdated != null) {
            condMap.put("endLastUpdated", endLastUpdated / 1000);
        }

        condMap.put("brandId", brandId);
        condMap.put("image", image);
        condMap.put("orderBy", orderBy);
        condMap.put("desc", desc);

        List<Map<String, Object>> listRes = spuService.getSpuListByCond(condMap);
        if (listRes != null) {
            return Response.status(StatusCode.SUCCESS).data(listRes);
        } else {
            return Response.status(StatusCode.FAILURE).data("");
        }
    }

    @RequestMapping("/spus/count")
    public Response getSpuCountByCond(@RequestParam(value = "isExact", required = false) Integer isExact,
            @RequestParam(value = "designerId", required = false) String designerId, @RequestParam(value = "colorCode", required = false) String colorCode,
            @RequestParam(value = "spuName", required = false) String spuName, @RequestParam(value = "seasonCode", required = false) String seasonCode,
            @RequestParam(value = "begLastUpdated", required = false) Long begLastUpdated,
            @RequestParam(value = "endLastUpdated", required = false) Long endLastUpdated, @RequestParam(value = "brandId", required = false) Integer brandId,
            @RequestParam(value = "image", required = false) Integer image

    ) {
        Map<String, Object> condMap = new HashMap<>();
        condMap.put("isExact", isExact);
        condMap.put("designerId", designerId);
        condMap.put("colorCode", colorCode);
        condMap.put("seasonCode", seasonCode);
        condMap.put("spuName", spuName);
        if (begLastUpdated != null) {
            condMap.put("begLastUpdated", begLastUpdated / 1000);
        }

        if (endLastUpdated != null) {
            condMap.put("endLastUpdated", endLastUpdated / 1000);
        }
        condMap.put("brandId", brandId);
        condMap.put("image", image);

        Map<String, Object> count = spuService.countSpu(condMap);
        return Response.status(StatusCode.SUCCESS).data(count);

    }

    @DeleteMapping(value = "/spus/{spuId}")
    public Response delSpu(@PathVariable(value = "spuId") Long spuId) {
        spuService.deleteSpu(spuId);
        return Response.success();
    }

    @DeleteMapping(value = "/spus")
    public Response delSpu(@RequestBody List<Long> spuIdList) {
        spuService.deleteSpus(spuIdList);
        return Response.success();
    }

    @GetMapping(value = "/spu/products")
    public Response getProductBySpuId(@RequestParam(value = "spuId") Long spuId, @RequestParam(value = "pageSize", required = false) Integer pageSize,
            @RequestParam(value = "pageNumber", required = false) Integer pageNo, @RequestParam(value = "orderBy", required = false) String orderBy,
            @RequestParam(value = "desc", required = false) String desc) {

        int start = ((pageNo == null || pageNo < 0) ? 0 : (pageNo - 1) * pageSize);
        int limit = ((pageSize == null || pageSize < 0) ? 25 : pageSize);

        Map<String, Object> condMap = new HashMap<>();
        condMap.put("spuId", spuId);
        condMap.put("orderBy", orderBy);
        condMap.put("desc", desc);
        condMap.put("start", start);
        condMap.put("limit", limit);

        return Response.status(1).data(productService.getProductBySpuId(condMap));
    }

    @GetMapping(value = "/spu/products/count")
    public Response getProductCount(@RequestParam(value = "spuId") Long spuId) {
        return Response.status(1).data(productService.getProductCount(spuId));
    }

    @PutMapping(value = "/spu/move/product")
    @Transactional
    public Response moveProductToSpu(@SessionAttribute(value = "user") Map<String, Object> user, @RequestParam(value = "productId") Long productId,
            @RequestParam(value = "designerId") String designerId, @RequestParam(value = "colorCode") String colorCode) {
        Spu targetSpu = spuService.getSpuByDesignerAndColorCode(designerId, colorCode);
        Product p = productService.selectByPrimaryKey(productId);
        if (p == null) {
            throw new ValidateException(new ErrorResponse("找不到目标Product!"));
        }

        Spu srcSpu = spuService.getSpuById(p.getSpuId());

        if (targetSpu == null) {
            throw new ValidateException(new ErrorResponse("找不到目标Spu!"));
        }

        //记录日志
        SpuAggregateLog sal = new SpuAggregateLog();

        if (srcSpu != null) {
            sal.setSrcSpuId(srcSpu.getSpuId());
            sal.setSrcDesignerId(srcSpu.getDesignerId());
            sal.setSrcColorCode(srcSpu.getColorCode());
        }

        sal.setTargetSpuId(targetSpu.getSpuId());
        sal.setTargetDesignerId(targetSpu.getDesignerId());
        sal.setTargetColorCode(targetSpu.getColorCode());

        sal.setType(TYPE_MOVE_TO_EXISTS_SPU);
        sal.setProductId(p.getProductId());
        sal.setUserId((Long) user.get("userId"));
        spuService.saveAggregateLog(sal);

        //更新商品数据
        p.setSpuId(targetSpu.getSpuId());
        productService.updateByPrimaryKeySelective(p);

        //按照规则聚合图片
        spuService.dealBoutiqueImg(sal.getSrcSpuId(), sal.getTargetSpuId(), p.getProductId());

        return Response.success();
    }

    @PutMapping(value = "/spu/save")
    public Response updateSpuById(@SessionAttribute(value = "user") Map<String, Object> user, @RequestBody Spu spu) {
        if (spu.getSpuId() == null) {
            throw new ValidateException(new ErrorResponse("spuId cannot be null!"));
        }

        Spu dbSpu = spuService.getSpuById(spu.getSpuId());
        if ((spu.getSpuDescription() != null && !spu.getSpuDescription().equals(dbSpu.getSpuDescription())) || (spu.getSpuName() != null && !spu.getSpuName()
                .equals(dbSpu.getSpuName()))) {
            spu.setDescModify(true);
        }

        if ((spu.getModelImg() != null && spu.getModelImg().length() > 5) || (spu.getStreetImg() != null && spu.getStreetImg().length() > 5)) {
            spu.setImgModified(true);
        } else {
            spu.setImgModified(false);
        }

        spuService.updateSpuById(spu);

        spuLogService.addSpuOperateLog(SpuLogUtil.buildSaveSpuLog(ConvertUtil.toLong(user.get("userId")), dbSpu, spu));
        return Response.success();
    }

    @PutMapping(value = "/spus/{spuId}/products/{productId}")
    public Response unbindProductFromSpu(@PathVariable(value = "spuId") Long spuId, @PathVariable(value = "productId") Long productId) {
        spuService.unbindProductSpu(spuId, productId);
        return Response.success();
    }

    @PostMapping(value = "/spu/products/downloadImage")
    public Response getProductCount(@RequestBody Map<String, Object> params, HttpServletResponse httpServletResponse) {
        if (params.get("fileUrl") != null && StringUtils.isEmpty(params.get("fileUrl").toString())) {
            throw new ValidateException(new ErrorResponse("fileUrl cannot be null!"));
        }
        String fileName = String.valueOf(System.currentTimeMillis()) + ".jpg";

        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            //获取网络资源
            URL url = new URL(params.get("fileUrl").toString());
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            //超时响应时间为5秒
            conn.setConnectTimeout(5 * 1000);

            httpServletResponse.setHeader("Content-Type", "application/force-download");
            httpServletResponse.setHeader("Content-disposition", "attachment; filename=" + fileName);
            //构造读取流
            bis = new BufferedInputStream(conn.getInputStream());
            //构造输出流
            bos = new BufferedOutputStream(httpServletResponse.getOutputStream());
            byte[] buff = new byte[1024];
            int bytesRead;
            //每次读取缓存大小的流，写到输出流
            while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
                bos.write(buff, 0, bytesRead);
            }
            httpServletResponse.flushBuffer();//将所有的读取的流返回给客户端
        } catch (Exception e) {
            e.printStackTrace();
            throw new ValidateException(new ErrorResponse("file download failed!"));
        } finally {
            try {
                if (null != bis) {
                    bis.close();
                }
                if (null != bos) {
                    bos.close();
                }
            } catch (IOException e) {
                LOGGER.error("文件下载失败！", e);
            }
        }
        return Response.success();
    }

    @PostMapping(value = "/spu/exception/product")
    public Response removeProductToException(@SessionAttribute(value = "user") Map<String, Object> user, @RequestBody Map<String, String> param) {
        Long productId = ConvertUtil.toLong(param.get("productId"));
        Long spuId = ConvertUtil.toLong(param.get("spuId"));

        SpuExceptionProduct spuExceptionProduct = new SpuExceptionProduct();
        spuExceptionProduct.setProductId(productId);
        spuExceptionProduct.setSpuId(spuId);
        spuService.addSpuExceptionProduct(ConvertUtil.toLong(user.get("userId")), spuExceptionProduct);
        return Response.success();
    }

    @PostMapping(value = "/spu/season/process")
    public Response processSPUSeason(@SessionAttribute(value = "user") Map<String, Object> user, @RequestBody Map<String, String> param) {
        Long userId = ConvertUtil.toLong(user.get("userId"));
        spuService.processSpuWithSeason();
        LOGGER.info("Start to process spu for season different, user {}.", userId);
        return Response.success();
    }

    @PostMapping(value = "/spu/season/processone/{spuId}")
    public Response processOneSPUSeason(@SessionAttribute(value = "user") Map<String, Object> user, @PathVariable(value = "spuId") Long spuId) {
        Long userId = ConvertUtil.toLong(user.get("userId"));
        LOGGER.info("Start to process one spu {} for season different, user {}.", spuId, userId);
        spuService.processOneSpuWithSeason(spuService.getSpuById(spuId));
        return Response.success();
    }

}
